<template>
  <div class="app-container">
    <div class="search-container">
      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
        <el-form-item prop="roleName" label="角色名称">
          <el-input v-model="queryParams.roleName" placeholder="角色名称" clearable @keyup.enter="handleQuery" />
        </el-form-item>

        <el-form-item label="时间期间">
          <el-select v-model="queryParams.dataType">
            <el-option v-for="item in dateTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>

        <el-form-item>
          <date-picker v-model:start="queryParams.startTime" v-model:end="queryParams.endTime" />
        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="handleQuery">
            <template #icon><ep-Search /></template>
            搜索
          </el-button>
          <el-button @click="handleResetQuery">
            <template #icon><ep-Refresh /></template>
            重置
          </el-button>
        </el-form-item>
      </el-form>
    </div>
    <el-card shadow="never">
      <template #header>
        <div class="flex-x-b">
          <el-button type="success" @click="handleOpenDialog()">
            <template #icon><ep-Plus /></template>
            新增
          </el-button>
          <el-button @click="exportList">
            <template #icon><ep-Download /></template>
            导出
          </el-button>
        </div>
      </template>

      <el-table ref="dataTableRef" v-auto-h v-loading="loading" :data="roleList" highlight-current-row border>
        <el-table-column label="角色名称" prop="roleName" />
        <el-table-column label="角色说明" prop="roleDesc" />
        <el-table-column label="更新时间" prop="updateTime" />
        <el-table-column label="创建时间" prop="createTime" />

        <el-table-column fixed="right" label="操作" width="220">
          <template #default="{ row }">
            <el-button type="primary" size="small" link @click="handleOpenAssignPermDialog(row)">
              <template #icon><ep-Position /></template>
              分配权限
            </el-button>
            <el-button type="primary" size="small" link @click="handleOpenDialog(row)">
              <template #icon><ep-Edit /></template>
              编辑
            </el-button>
            <el-button type="danger" size="small" link @click="handleDelete(row.roleId)">
              <template #icon><ep-Delete /></template>
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-model:page="current" v-model:pagesize="pageSize" :total="total" />
    </el-card>

    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" @close="handleCloseDialog">
      <el-form ref="roleFormRef" :model="formData" :rules="rules" label-width="100px">
        <el-form-item label="角色名称" prop="roleName">
          <el-input v-model="formData.roleName" placeholder="请输入角色名称" />
        </el-form-item>

        <el-form-item label="角色说明" prop="roleDesc">
          <el-input v-model="formData.roleDesc" placeholder="请输入角色说明" />
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确 定</el-button>
          <el-button @click="handleCloseDialog">取 消</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 分配权限弹窗 -->
    <el-drawer v-model="assignPermDialogVisible" :title="'【' + checkedRole.roleName + '】权限分配'" size="500">
      <div class="flex-x-b">
        <el-input v-model="permKeywords" clearable placeholder="菜单权限名称">
          <template #prefix>
            <ep-Search />
          </template>
        </el-input>

        <div class="flex-c ml-20">
          <el-button type="primary" size="small" plain @click="togglePermTree">
            <template #icon>
              <ep-Switch />
            </template>
            {{ isExpanded ? '收缩' : '展开' }}
          </el-button>
          <el-checkbox v-model="parentChildLinked" class="ml-20" @change="handleParentChildLinkedChange">父子联动</el-checkbox>

          <el-tooltip placement="bottom">
            <template #content>如果只需勾选菜单权限，不需要勾选子菜单或者按钮权限，请关闭父子联动</template>
            <el-icon class="ml-5 color-[--el-color-primary] inline-block cursor-pointer">
              <ep-QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
      </div>

      <el-tree
        ref="permTreeRef"
        node-key="id"
        show-checkbox
        :data="menuPermOptions"
        :filter-node-method="handlePermFilter"
        :default-expand-all="true"
        :check-strictly="!parentChildLinked"
        class="mt-20"
      ></el-tree>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleAssignPermSubmit">确 定</el-button>
          <el-button @click="assignPermDialogVisible = false">取 消</el-button>
        </div>
      </template>
    </el-drawer>
  </div>
</template>

<script lang="ts" setup>
import { getRoleList, exportRoleList, saveRole, removeRole, getRoleTreeByRoleId } from '@/api/system/role'
import { getTreeByParentId, type MenuData } from '@/api/system/menu'
import { usePagination } from '@/hooks/useRequest'
import type { RolePageQuery, RoleData, RoleForm } from '@/api/system/role'
import type { TreeInstance, FormInstance } from 'element-plus'
import type Node from 'element-plus/es/components/tree/src/model/node'

interface CheckedRole {
  roleId?: string
  roleName?: string
}

const queryFormRef = ref<FormInstance>()
const roleFormRef = ref<FormInstance>()
const permTreeRef = ref<TreeInstance>()

const initQueryParams: RolePageQuery = {
  nowPage: 1,
  pageSize: 10,
  dataType: 1,
  startTime: '',
  endTime: ''
}

const queryParams = ref<RolePageQuery>({ ...initQueryParams })

const { data, loading, run, total, current, pageSize } = usePagination(getRoleList, {
  defaultParams: [queryParams.value]
})

const roleList = computed(() => data.value?.result.records || [])

// 菜单权限下拉
const menuPermOptions = ref<MenuData[]>([])

const dateTypeOptions = ref<OptionType[]>([
  { value: 1, label: '创建时间' },
  { value: 2, label: '更新时间' }
])

const formData = reactive<RoleForm>({
  roleName: '',
  roleDesc: ''
})

const rules = reactive({
  roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
  roleDesc: [{ required: true, message: '请输入角色说明', trigger: 'blur' }]
})

const permKeywords = ref('')
const isExpanded = ref(true)

const parentChildLinked = ref(true)

const checkedRole = ref<CheckedRole>({})
const assignPermDialogVisible = ref(false)

const dialog = reactive({
  title: '',
  visible: false
})

const handleQuery = () => {
  run(queryParams.value)
}

const handleResetQuery = () => {
  queryFormRef.value.resetFields()
  queryParams.value = { ...initQueryParams }
  handleQuery()
}

const exportList = () => {
  exportRoleList(queryParams.value)
}

const handleOpenDialog = async (row?: RoleData) => {
  dialog.visible = true
  if (row) {
    dialog.title = '修改角色'
    await nextTick()
    formData.roleName = row.roleName
    formData.roleDesc = row.roleDesc
    formData.roleId = row.roleId
  } else {
    dialog.title = '新增角色'
  }
}

const handleCloseDialog = () => {
  roleFormRef.value.resetFields()
  roleFormRef.value.clearValidate()

  formData.roleId = undefined
  dialog.visible = false
}

const handleSubmit = () => {
  roleFormRef.value.validate(valid => {
    if (valid) {
      loading.value = true

      saveRole(formData)
        .then(() => {
          ElMessage.success(formData.roleId ? '修改成功' : '新增成功')
          handleCloseDialog()
          handleQuery()
        })
        .finally(() => (loading.value = false))
    }
  })
}

const handleDelete = (roleId: string) => {
  ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    loading.value = true
    removeRole(roleId)
      .then(() => {
        ElMessage.success('删除成功')
        handleQuery()
      })
      .finally(() => (loading.value = false))
  })
}

const handleOpenAssignPermDialog = async (row: RoleData) => {
  assignPermDialogVisible.value = true
  loading.value = true

  checkedRole.value.roleId = row.roleId
  checkedRole.value.roleName = row.roleName

  // 获取所有的菜单
  const res = await getTreeByParentId()
  menuPermOptions.value = res.result

  // 回显角色已拥有的菜单
  getRoleTreeByRoleId(row.roleId)
    .then(data => {
      const checkedMenuIds = data.result || []
      checkedMenuIds.forEach(menuId => permTreeRef.value!.setChecked(menuId, true, false))
    })
    .finally(() => {
      loading.value = false
    })
}

const handleAssignPermSubmit = () => {
  const roleId = checkedRole.value.roleId
  if (roleId) {
    const checkedMenuIds: string[] = permTreeRef.value!.getCheckedNodes(false, true).map((node: { [key: string]: any }) => node.id)

    loading.value = true
    saveRole({ menuIds: checkedMenuIds.join(','), ...checkedRole.value })
      .then(() => {
        ElMessage.success('分配权限成功')
        assignPermDialogVisible.value = false
        handleQuery()
      })
      .finally(() => {
        loading.value = false
      })
  }
}

/** 展开/收缩 菜单权限树  */
function togglePermTree() {
  isExpanded.value = !isExpanded.value
  if (permTreeRef.value) {
    Object.values(permTreeRef.value.store.nodesMap).forEach((node: Node) => {
      if (isExpanded.value) {
        node.expand()
      } else {
        node.collapse()
      }
    })
  }
}

function handleParentChildLinkedChange(val: any) {
  parentChildLinked.value = val
}

// 对树节点进行筛选， 返回 false 则表示这个节点会被隐藏
const handlePermFilter = (value: string, data: { [key: string]: any }) => {
  if (!value) return true
  return data.label.includes(value)
}

watch(permKeywords, val => {
  permTreeRef.value!.filter(val)
})
</script>
<style lang="scss" scoped></style>
